#ifndef __BUOLA_SCENE_CMESHBUILDER_H__
#define __BUOLA_SCENE_CMESHBUILDER_H__

#include <buola/scene/cmesh.h>

namespace buola { namespace scene {

class CMeshBuilder : public UShared
{
    template<typename tType>
    struct SChannel
    {
        std::vector<tType> mData;
        std::vector<int> mVertices; //!<for each vertex, an index into mData

        const tType &GetVertex(int i)
        {
            if(i==-1)
            {
                throw XRange("retrieving channel value -1");
            }
            return mData[mVertices[i]];
        }

        bool IsEmpty()    {   return mVertices.empty();   }
    };
    
    struct SSubMesh
    {
        std::string mName;
        std::vector<int> mFaces;
        EPrimitive mPrimitiveType;
    };

public:
    CMeshBuilder();
    ~CMeshBuilder();

    void SetPosition(const std::vector<mat::CVec3d> &pPosition);
    void SetNormal(const std::vector<mat::CVec3d> &pNormal);
    void SetTexCoord(const std::vector<mat::CVec3d> &pTexCoord);

    void SetVertices(const std::vector<int> &pPosition,const std::vector<int> &pNormal,
                     const std::vector<int> &pTexCoord=std::vector<int>());

    void SetFaces(const std::vector<int> &pFaces);
    void SetMaterial(const std::vector<mat::CVec4d> &pMaterials,const std::vector<int> &pIndices);
    
    void AddSubMesh(const std::string &pName,const std::vector<int> &pFaces,EPrimitive pPrimitiveType);

    void Scale(double pScale);
    void CalcNormals();
    void SmoothNormals();
    void SmoothSkinning();
    void AssignSkinIndex(const std::string &pSubMesh,int pIndex);
    void AssignSkinIndices(const std::string &pSubMesh,CBone *pBone);

    PMesh BuildMesh(EPrimitive pPrimitiveType=EPrimitive::TRIANGLE_FAN);
    
private:
    SChannel<mat::CVec3d> mPosition;
    SChannel<mat::CVec3d> mNormal;
    SChannel<mat::CVec3d> mTexCoord;
    SChannel<mat::CVec4d> mMaterial;
    SChannel<uint32_t> mSkinIndex;
    SChannel<float> mSkinWeight;

    std::vector<int> mFaces;    //!< start of each primitive, as an index into mVertices of the channels
    std::vector<SSubMesh> mSubMeshes;
    
    bool mHaveBOs;
};

/*namespace scene*/ } /*namespace buola*/ }

#endif
